﻿using Arch.Core;
using Meow.Core.Graphics;
using Meow.Core.Graphics.Renderables;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace Meow.Core.Simulation;

public class CameraPrepareForRenderSys : ECS_System, IRenderSystem
{
    QueryDescription cameraQuery = new QueryDescription()
                                        .WithAll<SimpleCamera>();

    QueryDescription renderableQuery = new QueryDescription()
                                .WithAll<C_Renderable>();

    List<ICamera> cameras = new List<ICamera>();
    public CameraPrepareForRenderSys(World world, Scene scene) : base(world, scene)
    {
    }

    void IRenderSystem.Render(Microsoft.Xna.Framework.GraphicsDeviceManager gdm, Microsoft.Xna.Framework.GameTime gameTime, float totalElapsedTime, int tick)
    {
        cameras.Clear();


        world.Query(in cameraQuery, (ref SimpleCamera camera, ref Viewport viewport) =>
        {
            camera.UpdateAspectRatioWithViewport();
            camera.UpdateCullingFrustum();
            camera.ClearEntitiesInSight();
            cameras.Add(camera);

        });

        var culling = new CameraCulling(cameras);
        world.InlineParallelEntityQuery<CameraCulling, C_Renderable>(in renderableQuery, ref culling);
    }

    struct CameraCulling : IForEachWithEntity<C_Renderable>
    {
        List<ICamera> cameras;
        public CameraCulling(List<ICamera> cameras)
        {
            this.cameras = cameras;

        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]

        void IForEachWithEntity<C_Renderable>.Update(Entity entity, ref C_Renderable renderable)
        {
            renderable.ToDraw = false;

            foreach (var cam in cameras)
            {
                if (cam.CullingFrustum.Intersects(renderable.BoundingSphere))
                {
                    renderable.ToDraw = true;
                    cam.AddEntityInSight(entity);
                }
            }
        }
    }
}
